package org.peterf.foxish.component;

import org.peterf.foxish.R;
import org.peterf.foxish.buffer.IndexBufferB;
import org.peterf.foxish.buffer.VertexBufferF;
import org.peterf.foxish.camera.Camera;
import org.peterf.foxish.component.property.Focusable;
import org.peterf.foxish.math.transformation.Matrix2D;
import org.peterf.foxish.math.transformation.SpriteMatrix;
import org.peterf.foxish.opengl20.OpenGLUtil.BufferUsage;
import org.peterf.foxish.program.ProgramRepository;

/**
 * A {@link RectangleSprite} is a {@link Sprite} with a rectangle shape.
 * 
 * @author peter
 * 
 */
public class RectangleSprite extends Sprite implements Focusable {

    /**
     * Program parameter location for color.
     */
    protected int colorLoc;

    /**
     * A preallocated vector storing finger positions of the last touch. This is
     * useful for {@link #isInside(float, float)}, because the reverse model
     * view matrix could be applied to this vector, so as to decide whether the
     * touch is inside this.
     */
    protected float[] fingerPoint = new float[2];

    /**
     * Program parameter location for model view matrix.
     */
    protected int mvLoc;

    /**
     * Program parameter location for per-vertex positions.
     */
    protected int posLoc;
    
    protected SpriteMatrix reversedMatrix = matrix.getReversed(true);

    /**
     * The left top x in model coordinates.
     */
    protected float x1;

    /**
     * The right bottom x in model coordinates.
     */
    protected float x2;

    /**
     * The left top y in model coordinates.
     */
    protected float y1;

    /**
     * The right bottom y in model coordinates.
     */
    protected float y2;

    /**
     * Create a rectangle with a given size.
     * 
     * @param x1
     *            The left top x in model coordinates.
     * @param y1
     *            The left top y in model coordinates.
     * @param x2
     *            The right bottom x in model coordinates.
     * @param y2
     *            The right bottom y in model coordinates.
     */
    public RectangleSprite(float x1, float y1, float x2, float y2) {
        this.x1 = x1;
        this.x2 = x2;
        this.y1 = y1;
        this.y2 = y2;
    }

    /**
     * Create an empty rectangle. If you decide to use this version of
     * {@link #onCreate()}, be sure that rectangle coordinates are set properly
     * before calling it.
     */
    protected RectangleSprite() {
        this(0.0f, 0.0f, 0.0f, 0.0f);
    }

    public float getHeight() {
        return y1 - y2;
    }

    public float getWidth() {
        return x2 - x1;
    }

    /**
     * Test whether a given world coordinates pair is inside this.
     */
    public boolean isInside(float x, float y) {
        fingerPoint[0] = x;
        fingerPoint[1] = y;
        matrix.debug();
        reversedMatrix.refactor();
        reversedMatrix.debug();
        reversedMatrix.apply(fingerPoint);
        return fingerPoint[0] >= x1 && fingerPoint[0] <= x2
                && fingerPoint[1] >= y2 && fingerPoint[1] <= y1;
    }

    /**
     * Vertex information as well as the program is created and uploaded here.
     */
    @Override
    public void onCreate() {
        float ps[] = new float[] { x1, y1, x1, -y1, x2, -y2, x2, y2 };
        byte is[] = new byte[] { 0, 1, 2, 3 };
        vertexBuffer = new VertexBufferF(ps, BufferUsage.STATIC);
        indexBuffer = new IndexBufferB(is, BufferUsage.STATIC);
        onRecreate();
    }

    /**
     * Vertex information as well as the program is destroyed here.
     */
    @Override
    public void onDestroy() {
        vertexBuffer.delete();
        indexBuffer.delete();
        program.delete();
    }

    /**
     * Draws the rectangle with given vertex positions, transparency, model view
     * matrix and color.
     */
    @Override
    public synchronized void onDraw(Camera camera, float elapsed) {
        onUpdate(elapsed);
        if (enabled) {
            program.use(camera);
            program.assignAttrib(posLoc, 0, 2);
            program.assignUniformMat4(mvLoc, matrix.getMatrix(), 0);
            program.assignUniformVec4(colorLoc, color, 0);
            program.drawTriangleStrip(0, 4);
        }
    }

    /**
     * Vertex information as well as the program is uploaded here.
     */
    @Override
    public void onRecreate() {
        vertexBuffer.upload();
        indexBuffer.upload();
        program = ProgramRepository.get(R.string.vertex_ucamera_umvtrans_apos,
                R.string.fragment_ucolor);
        program.setBuffer(vertexBuffer, indexBuffer);
        mvLoc = program.getUniformLoc(R.string.uniform_mvtrans);
        posLoc = program.getAttribLoc(R.string.attrib_position);
        colorLoc = program.getUniformLoc(R.string.uniform_color);
    }

}
